// 写出computed
let activeEffect
const data = {num: 1, num2: 2, num3: 3, num4: 4}
const bucket = new WeakMap()
// 新增
let effectStack = []

// 收集依赖
function track (target, key) {
  let depsMap = bucket.get(target)
  if (!depsMap) {
    bucket.set(target, depsMap = new Map())
  }
  let deps = depsMap.get(key)
  if (!deps) {
    depsMap.set(key, deps = new Set())
  }
  if (activeEffect) {
    deps.add(activeEffect)
    activeEffect.deps.push(deps)
  }
}

// 触发事件
function trigger (target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)
  const effectsToRun = new Set()
  effects.forEach(effect => {
    if (effect !== activeEffect) {
      effectsToRun.add(effect)
    }
  })

  effectsToRun.forEach(effect => {
    if (effect.options.schedule) {
      effect.options.schedule(effect)
    } else {
      effect()
    }
  })
}

// 代理
const obj = new Proxy(data, {
  get(target, key) {
    track(target, key)
    return target[key]
  },
  set(target, key, value) {
    target[key] = value
    trigger(target, key)
  }
})

function cleanup (effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i]
    deps.delete(effectFn)
  }
  effectFn.deps.length = 0
}

function effect (fn, options = {}) {
  const effectFn = () => {
    cleanup(effectFn)
    activeEffect = effectFn
    effectStack.push(effectFn)
    // 获取fn返回值
    const res = fn()
    effectStack.pop()
    activeEffect = effectStack[effectStack.length - 1]
    // 返回
    return res
  }
  effectFn.deps = []
  effectFn.options = options
  // 新增
  // 只有非lazy模式, 才会执行
  if(!options.lazy) {
    effectFn()
  }
  return effectFn
}

// === computed
// 1. 基本功能的实现
function computed1(getter) {
  const fn = effect(getter, {
    lazy: true
  })

  let obj = {
    get value() {
      return fn()
    }
  }
  return obj
}

const result1 = computed1(() => {
  console.log('computed1: 执行了一次')
  return obj.num + obj.num2
})

console.log(result1.value, 'computed1的值')
console.log(result1.value, 'computed2的值')

// 2. 去除重复执行
function computed2 (getter) {
  // 增加
  let dirty = true
  // 增加
  let value
  const fn = effect(getter, {
    lazy: true,
    schedule() {
      // 增加
      dirty = false
    }
  })

  let obj = {
    get value() {
       // 增加
      if (dirty) {
        value = fn()
        dirty = false
        return value
      } else {
        return value
      }
    }
  }
  return obj
}

const result2 = computed2(() => {
  console.log('computed2: 执行了一次')
  return obj.num + obj.num2
})
console.log(result2.value, 'computed2的值')
console.log(result2.value, 'computed2的值')

// 3. 结果具备响应式

// 问题:
// 前面的computed2虽然具备了懒计算和去重功能, 但是并不具备响应式能力
effect(() => {
  const result = computed2(() => obj.num + obj.num2)
  console.log(result.value, 'computed2更新结果')
})

obj.num++ // 这根本不会导致上面的副作用函数再次执行


// 所以要将这个副作用函数也设法纳入监听体系!
function computed3 (getter) {
  let value
  let dirty = true
  let obj = {
    get value() {
      if (dirty) {
        value = fn()
        dirty = false
      }
      // 注意, 此时的activeEffect应该是最外层的那个副作用函数
      track(obj, 'value')
      return value
    }
  }
  const fn = effect(getter, {
    lazy: true,
    schedule() {
      if (!dirty) {
        dirty = true
        // 触发
        trigger(obj, 'value')
      }
    }
  })
  return obj
}

effect(() => {
  const result = computed3(() => obj.num3 + obj.num4)
  console.log(result.value, 'computed3更新结果')
})

obj.num3++
obj.num4++


